home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Portable Patmos 1.1 / patmos-src / src / sock_udp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-19  |  8.9 KB  |  420 lines  |  [TEXT/R*ch]

  1. /*
  2.  * BSD-style socket emulation library for the Mac
  3.  * Original author: Tom Milligan
  4.  * Current author: Charlie Reiman - creiman@ncsa.uiuc.edu
  5.  *
  6.  * This source file is placed in the public domian.
  7.  * Any resemblance to NCSA Telnet, living or dead, is purely coincidental.
  8.  *
  9.  *      National Center for Supercomputing Applications
  10.  *      152 Computing Applications Building
  11.  *      605 E. Springfield Ave.
  12.  *      Champaign, IL  61820
  13.  */
  14.  
  15. #ifdef USEDUMP
  16. # pragma load "Socket.dump"
  17.  
  18. #else
  19. # include <Events.h>
  20. # include <Memory.h>
  21. # include <Errors.h>
  22. # include <Types.h>
  23. # include <OSUtils.h>
  24. # include <Stdio.h>
  25.  
  26. # include <s_types.h>
  27. # include <neti_in.h>
  28. # include <neterrno.h>
  29. # include <s_socket.h>
  30. # include <s_time.h>
  31. # include <s_uio.h>
  32.  
  33. # include "sock_str.h"
  34. # include "sock_int.h"
  35.  
  36. #endif
  37.  
  38. extern SocketPtr sockets;
  39. extern SpinFn spinroutine;
  40.  
  41. #if 0
  42. /*
  43.  * asynchronous notification routine 
  44.  */
  45. static int notified = 0;
  46. static int lastNotifyCount = 0;
  47.  
  48. static StreamPtr notifyUdpStream;
  49. static unsigned short notifyEventCode;
  50. static Ptr notifyUserDataPtr;
  51. static unsigned short notifyTerminReason;
  52. static struct ICMPReport *notifyIcmpMsg;
  53.  
  54. pascal void sock_udp_notify(
  55.     StreamPtr udpStream,
  56.     unsigned short eventCode,
  57.     Ptr userDataPtr,
  58.     struct ICMPReport *icmpMsg)
  59. {
  60.     notified++;
  61.  
  62.     notifyUdpStream = udpStream;
  63.     notifyEventCode = eventCode;
  64.     notifyUserDataPtr = userDataPtr;
  65.     notifyIcmpMsg = icmpMsg;
  66. }
  67.  
  68. static char *eventNames[] = 
  69. {
  70.     "event 0",
  71.     "data arrival",
  72.     "ICMP message"
  73. };
  74. static char *icmpMessages[] =
  75. {
  76.     "net unreachable",
  77.     "host unreachable",
  78.     "protocol unreachable",
  79.     "port unreachable",
  80.     "fragmentation required",
  81.     "source route failed",
  82.     "time exceeded",
  83.     "parameter problem",
  84.     "missing required option"
  85. };
  86.  
  87.  
  88. int udpCheckNotify()
  89. {
  90.     if (notified == lastNotifyCount)
  91.         return(0);
  92.     
  93.     lastNotifyCount = notified;
  94.     dprintf("notify count is now %d\n",lastNotifyCount);
  95.     dprintf("stream %08x\n",notifyUdpStream);
  96.     dprintf("event %d '%s'\n",notifyEventCode,eventNames[notifyEventCode]);
  97.     if (notifyEventCode == UDPDataArrival)
  98.         dprintf("%d bytes\n",notifyTerminReason/*!?*/);
  99.     dprintf("icmp msg %08x\n",notifyIcmpMsg);
  100.     if (notifyEventCode == UDPICMPReceived)
  101.     {
  102.         dprintf("stream %08x\n",notifyIcmpMsg->streamPtr);
  103.         dprintf("local %08x/%d\n",notifyIcmpMsg->localHost,notifyIcmpMsg->localPort);
  104.         dprintf("remote %08x/%d\n",notifyIcmpMsg->remoteHost,notifyIcmpMsg->remotePort);
  105.         dprintf("%s\n",icmpMessages[notifyIcmpMsg->reportType]);
  106.         dprintf("optionalAddlInfo %04x\n",notifyIcmpMsg->optionalAddlInfo);
  107.         dprintf("optionalAddlInfoPtr %08x\n",notifyIcmpMsg->optionalAddlInfoPtr);
  108.     }
  109.     dprintf("userdata %s\n",notifyUserDataPtr);
  110.     return(1);
  111. }
  112.  
  113. #endif
  114.  
  115. /*
  116.  * sock_udp_new_stream()  - create the MacTCP stream for this socket. not
  117.  *                          called till the last minute while we wait for
  118.  *                          a bind to come in.
  119.  *
  120.  *                          called from whichever of connect, recv, send or 
  121.  *                          select (can_recv or can_send) is called first.
  122.  */
  123. int sock_udp_new_stream(
  124.     SocketPtr sp)
  125. {
  126. OSErr                 io;
  127. StreamHashEntPtr     shep;
  128.     
  129. #if SOCK_UDP_DEBUG >= 2
  130.     dprintf("sock_udp_new_stream: sp %08x port %d\n", sp, sp->sa.sin_port);
  131. #endif
  132.     
  133.     if ( (io=xUDPCreate(sp, STREAM_BUFFER_SIZE, sp->sa.sin_port)) != noErr )
  134.         return(sock_err(io));
  135.         
  136.     sp->sstate = SOCK_STATE_UNCONNECTED;
  137.     
  138.     if (shep = sock_new_shep(sp->stream))
  139.         {
  140.         shep -> stream = sp->stream;
  141.         shep -> socket = sp;
  142.         }
  143.     else
  144.         return -1;
  145.         
  146.     sp-> recvd = 0;
  147.     sp-> recvBuf = 0;
  148.     sp-> asyncerr = inProgress;
  149.     
  150.     /* start up the read ahead */
  151.     return(sock_udp_read_ahead(sp));
  152. }
  153.  
  154.  
  155. /*
  156.  *    sock_udp_connect() - sets the peer process we will be talking to
  157.  */
  158. int sock_udp_connect(
  159.     SocketPtr sp,
  160.     struct sockaddr_in *addr)
  161. {
  162.     int status;
  163.     
  164.     /* make the stream if its not made already */
  165.     if (sp->sstate == SOCK_STATE_NO_STREAM)
  166.     {
  167.         status = sock_udp_new_stream(sp);
  168.         if (status != 0)
  169.             return(status);
  170.     }
  171.     
  172.     /* record our peer */
  173.     sp->peer.sin_len = sizeof(struct sockaddr_in);
  174.     sp->peer.sin_addr.s_addr = addr->sin_addr.s_addr;
  175.     sp->peer.sin_port = addr->sin_port;
  176.     sp->peer.sin_family = AF_INET;
  177.     sp->sstate = SOCK_STATE_CONNECTED;
  178.     
  179.     if (sp-> recvBuf) {
  180.         xUDPBfrReturn(sp);
  181.         }
  182.     /* flush the read-ahead buffer if its not from our new friend */
  183.     (void) sock_udp_can_recv(sp);
  184.     
  185.     return(0);
  186. }
  187.  
  188. /*
  189.  * sock_udp_read_ahead() - start up the one packet read-ahead
  190.  *
  191.  *                         called from new_stream, recv and can_recv
  192.  */
  193. static int sock_udp_read_ahead(SocketPtr sp)
  194.     {
  195.     OSErr io;
  196.     void sock_udp_read_ahead_done(UDPiopb *pb);
  197.     
  198.     io = xUDPRead(sp, (UDPIOCompletionProc)sock_udp_read_ahead_done);
  199.     if (io != noErr) 
  200.         return(sock_err(io));
  201.  
  202.     return(0);
  203.     }
  204.  
  205. /*
  206.  * sock_udp_return_buffer() - return the receive buffer to MacTCP
  207.  */
  208. static 
  209. int sock_udp_return_buffer(
  210.     SocketPtr sp)
  211. {
  212.     OSErr io;
  213.     
  214.     if (sp->recvBuf)
  215.     {
  216.         io = xUDPBfrReturn(sp);
  217.         if (io != noErr)
  218.             return(sock_err(io));
  219.     }
  220.     return(noErr);
  221. }
  222.  
  223. /*
  224.  * sock_udp_recv()
  225.  *
  226.  * returns bytes received or -1 and errno
  227.  */
  228. int sock_udp_recv(
  229.     SocketPtr sp,
  230.     char *buffer,
  231.     int buflen,
  232.     int flags,
  233.     struct sockaddr_in *from,
  234.     int *fromlen)
  235. {
  236. #pragma unused(flags)
  237.     
  238. #if SOCK_UDP_DEBUG >= 2
  239.     dprintf("sock_udp_recv: sp %08x buflen %d state %04x\n", sp,buflen,sp->sstate);
  240. #endif
  241.  
  242.     /* make the stream if its not made already */
  243.     if (sp->sstate == SOCK_STATE_NO_STREAM)
  244.     {
  245.         int status = sock_udp_new_stream(sp);
  246.         if (status != 0)
  247.             return(status);
  248.     }
  249.     
  250.     /* dont block a non-blocking socket */
  251.     if (sp->nonblocking && !sock_udp_can_recv(sp))
  252.         return(sock_err(EWOULDBLOCK));
  253.     
  254.     SPIN(!sock_udp_can_recv(sp),SP_UDP_READ,0)
  255.  
  256.     if (sp->asyncerr!=noErr)
  257.         return(sock_err(sp->asyncerr));
  258.  
  259.     /* return the data to the user - truncate the packet if necessary */
  260.     buflen = min(buflen,sp->recvd);    
  261.     BlockMove(sp->recvBuf,buffer,buflen);
  262.     
  263. #if (SOCK_UDP_DEBUG >= 7) || defined(UDP_PACKET_TRACE)
  264. /*
  265.     hex_dump(buffer, buflen, "udp from %08x/%d\n",
  266.             sp->apb.pb.udp.csParam.receive.remoteHost,
  267.             sp->apb.pb.udp.csParam.receive.remotePort);
  268. */
  269. #endif
  270.  
  271.     if (from != NULL && *fromlen >= sizeof(struct sockaddr_in))
  272.         {
  273.         (*from) = sp->peer;
  274.         (*fromlen) = sizeof (struct sockaddr_in);
  275.         }    
  276.     
  277.     /* continue the read-ahead - errors which occur */
  278.     /* here will show up next time around */
  279.     (void) sock_udp_return_buffer(sp);
  280.     (void) sock_udp_read_ahead(sp);
  281.  
  282.     return(buflen);
  283. }
  284.  
  285.  
  286. /*
  287.  *    sock_udp_can_recv() - returns non-zero if a packet has arrived.
  288.  *
  289.  *                        Used by select, connect and recv.
  290.  */
  291. int sock_udp_can_recv(SocketPtr sp)
  292.     {
  293.     if (sp->sstate == SOCK_STATE_NO_STREAM)
  294.         {
  295.         int status = sock_udp_new_stream(sp);
  296.         if (status != 0)
  297.             return(-1);
  298.         }
  299.     
  300.     if (sp->asyncerr == inProgress)
  301.         return(0);
  302.     
  303.     return 1;  // must recieve if not reading, even if an error occured - must handle error.
  304.     }
  305.  
  306. /*
  307.  *    sock_udp_send() - send the data in the (already prepared) wds
  308.  *
  309.  *    returns bytes sent or -1 and errno
  310.  */
  311. int sock_udp_send(SocketPtr sp,struct sockaddr_in *to,char *buffer,int count,int flags)
  312.     {
  313. #pragma unused(flags)
  314.     miniwds  awds;
  315.     OSErr    io;
  316.     void sock_udp_send_done(UDPiopb *pb);
  317.     
  318. #if SOCK_UDP_DEBUG >= 2
  319.     dprintf("sock_udp_send: %08x state %04x\n",sp,sp->sstate);
  320. #endif
  321.  
  322.     /* make the stream if its not made already */
  323.     if (sp->sstate == SOCK_STATE_NO_STREAM)
  324.         {
  325.         io = sock_udp_new_stream(sp);
  326.         if (io != 0)
  327.             return(io);
  328.         }
  329.     
  330.     if ( count > UDP_MAX_MSG )
  331.         return sock_err(EMSGSIZE);
  332.         
  333.     awds.terminus = 0;
  334.     awds.length = count;
  335.     awds.ptr = buffer;
  336.     
  337.     // if no address passed, hope we have one already in peer field
  338.     if (to == NULL)
  339.         if (sp->peer.sin_len)
  340.             to = &sp->peer;
  341.         else
  342.             return (sock_err(EHOSTUNREACH));
  343.     
  344.     io = xUDPWrite(sp, to->sin_addr.s_addr,to->sin_port, &awds, 
  345.             (UDPIOCompletionProc)sock_udp_send_done);
  346.     
  347.     if (io != noErr )
  348.         return(io);
  349.     
  350.     // get sneaky. compl. proc sets ptr to nil on completion, and puts result code in
  351.     // terminus field.
  352.     
  353.     SPIN(awds.ptr != NULL,SP_UDP_WRITE,count)
  354.     return (awds.terminus);
  355.     }
  356.  
  357. /*
  358.  *    sock_udp_can_send() - returns non-zero if a write will not block
  359.  */
  360. int sock_udp_can_send(SocketPtr sp)
  361.     {
  362.     if (sp->sstate == SOCK_STATE_NO_STREAM)
  363.         {
  364.         if ( sock_udp_new_stream(sp) != 0 )
  365.             return(-1);
  366.         }
  367.     
  368.     return (1);
  369.     }
  370.  
  371. /*
  372.  *    sock_udp_close()
  373.  */
  374. int sock_udp_close(SocketPtr sp)
  375.     {
  376.     OSErr io;
  377.     
  378.     if (sp->sstate == SOCK_STATE_NO_STREAM)
  379.         return(0);
  380.     io = xUDPRelease(sp);
  381.     if (io != noErr)
  382.         return(sock_err(io));
  383.     return(0);
  384.     }
  385.     
  386. #pragma segment SOCK_RESIDENT
  387. /*
  388.  * Interrupt routines - MUST BE IN A RESIDENT SEGMENT! Most important to 
  389.  * MacApp programmers
  390.  */
  391.     
  392.     
  393. /*
  394.  * sock_udp_send_done
  395.  */
  396.  
  397. static void sock_udp_send_done(UDPiopb *pb) {
  398.     ((miniwds *)pb->csParam.send.wdsPtr)->terminus = pb->ioResult;
  399.     ((miniwds *)pb->csParam.send.wdsPtr)->ptr = NULL;
  400.     }
  401.  
  402. /*
  403.  * sock_udp_read_ahead_done
  404.  */
  405. static void sock_udp_read_ahead_done(UDPiopb *pb) {
  406.     register    SocketPtr    sp;
  407.     
  408.     sp = sock_find_shep( pb->udpStream )->socket;
  409.     if (pb->ioResult == noErr) {
  410.         sp->recvBuf = pb->csParam.receive.rcvBuff;
  411.         sp->recvd   = pb->csParam.receive.rcvBuffLen;
  412.         }
  413.     else {
  414.         sp-> recvd = 0;
  415.         sp-> recvBuf = 0;
  416.         }
  417.     sp->asyncerr = pb->ioResult;
  418.     }
  419.  
  420.